#include "aio_thread.h"
#include "../global/head.h"
#include "../socket/head.h"
#include "../xos/head.h"
#include "../buf/head.h"
#include "aio_epoll_notify.h"
#include "aio_impl.h"
#include "aio_helper.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    aio_thread::aio_thread( aio_impl * pAioImpl ) : m_pAioImpl( pAioImpl )
    {
        m_bQuit = false;
        m_pThread = 0;
    }

    aio_thread::~aio_thread()
    {
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int aio_thread::init()
    {
        int nRet = 0;

        if( 0 == nRet )
        {
            nRet = g_pXosImpl->create( i_xos::XOS_OBJ_THREAD, ( void ** )&m_pThread );
        }

        if( 0 == nRet )
        {
            m_pThread->create( aio_thread::thread, this );
        }

        return nRet;
    }

    int aio_thread::term()
    {
        int nRet = 0;

        if( m_pThread )
        {
            m_bQuit = true;
            m_pAioImpl->m_pEpollNotify->set_event();
            m_pThread->wait();
            m_pThread->release();
            m_pThread = 0;
        }

        m_pAioImpl = 0;

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////
    // 

    void * aio_thread::thread( void * lpData )
    {
        aio_thread & obj = *( aio_thread * )lpData;
        aio_impl * lpAioImpl = obj.m_pAioImpl;
        aio_helper tool( lpAioImpl );

        int nRet = 0;

        while( 0 == nRet )
        {
            int nNum = epoll_wait( lpAioImpl->m_hEpoll, obj.m_event, sizeof( obj.m_event ) / sizeof( obj.m_event[0] ), lpAioImpl->m_nTimeout );

            if( obj.m_bQuit )
            {
                nRet = 1;
                continue;
            }

            // 
            // is timeout.
            // 
            if( nNum <= 0 )
            {
                tool.timeout();
                continue;
            }

            //
            // process net event.
            // 
            obj.run( nNum ); 
        }

        return 0;
    }

    int aio_thread::run( int nNum )
    {
        int nRet = 0;

        aio_helper tool( m_pAioImpl );

        for( int i = 0; i < nNum; ++i )
        {
            void * lpData = m_event[i].data.ptr;
            int nFlags = m_event[i].events;

            if( lpData != m_pAioImpl->m_pEpollNotify )
            {
                tool.epoll_proc( ( aio_key * )lpData, nFlags );
            }
            else
            {
                m_pAioImpl->m_pEpollNotify->reset();
                tool.user_request();
            }
        }

        return nRet;
    }

} // xos
